/*
Miranda 2 GDS plugin: a plugin for the free icq client Miranda-IM for MS Windows 
Copyright (C) 2000-5  Vladimir Vainer

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/


#include <windows.h>
#include <commctrl.h>
#include <string.h>
#include <stdio.h>
#include "resource.h"


#include "db2gds.h"


#define WM_TRAY_ICON_NOTIFY_MESSAGE (WM_USER + 1)

BOOL CALLBACK WizardIntroPageProc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK FinishedPageProc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK ContactsPageProc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK IndexPageProc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam);


extern HINSTANCE hInst;

HANDLE * g_hContacts = NULL;
HWND	 g_hwndDialog = NULL;
HWND     g_hwndParent = NULL;
HWND     g_hwndIndexDialog = NULL;

NOTIFYICONDATA g_iconData;

int				g_nCount = 0;
int				g_nCurrent = 0;
char			g_szToolTip[500];
static	int		BackgroundTimer = 100;
int				g_nIconIndex = -1;

DWORD			dwThreadId = 0;
HANDLE			hThread = NULL;
CRITICAL_SECTION Sect1;

void	FillContactsArray(HWND hdlg);
void	InitIndexDialog(HWND  hdlg);
DWORD  _stdcall IndexChats(void * pData); //pData is -> HWND
void	LogToFile(char * szUser,char * szBuddy,char * szMsg,DWORD & timespan,bool bIsSent);
void	UpdateInfoOnMsg(HWND hdlg,HANDLE hContact, int nProgress,int nTotal);
void	UpdateInfoOnContact(HWND hdlg,HANDLE hContact,int nTotal);

void	ActivateBackgroundMode();
void	OnTimer(HWND hWnd,UINT nId);
void	OnTrayNotify(WPARAM wParam, LPARAM lParam);


BOOL CALLBACK WizardIntroPageProc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	
	switch(message)
	{
		case WM_INITDIALOG:
		{
			SendMessage(GetParent(hdlg), WIZM_DISABLEBUTTON, 0, 0);
		return TRUE;
		}
		
		case WM_COMMAND:
		switch(LOWORD(wParam))
		{
			case IDOK:
				PostMessage(GetParent(hdlg), WIZM_GOTOPAGE, IDD_CONTACTS, (LPARAM)ContactsPageProc);
				break;
				
			case IDCANCEL:
				PostMessage(GetParent(hdlg), WM_CLOSE, 0, 0);
				break;
		}
		break;
	}
	return FALSE;
}

BOOL CALLBACK ContactsPageProc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	
	switch(message)
	{
		case WM_INITDIALOG:
		return TRUE;
		
		case WM_COMMAND:
		switch(LOWORD(wParam))
		{
			case IDC_BACK:
				PostMessage(GetParent(hdlg), WIZM_GOTOPAGE, IDD_WIZARDINTRO, (LPARAM)WizardIntroPageProc);
				break;
			case IDOK:
				FillContactsArray(hdlg);
				PostMessage(GetParent(hdlg), WIZM_GOTOPAGE, IDD_INDEX, (LPARAM)IndexPageProc);
				break;
				
			case IDCANCEL:
				PostMessage(GetParent(hdlg), WM_CLOSE, 0, 0);
				break;
		}
		break;
	}
	return FALSE;
}

BOOL CALLBACK IndexPageProc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	
	switch(message)
	{
		case WM_INITDIALOG:
			InitIndexDialog(hdlg);
			return TRUE;
		case WM_TIMER:
			OnTimer(hdlg,wParam);
			break;

		case WM_COMMAND:
		switch(LOWORD(wParam))
		{
			case IDC_BACK:
				PostMessage(GetParent(hdlg), WIZM_GOTOPAGE, IDD_CONTACTS, (LPARAM)ContactsPageProc);
				break;
			case IDOK:
			    if (hThread==NULL)
				{
					g_hwndParent = GetParent(hdlg);
					SendMessage(g_hwndParent, WIZM_DISABLEBUTTON, 0, 0);
					SendMessage(g_hwndParent, WIZM_DISABLEBUTTON, 2, 0);
					SetDlgItemText(g_hwndParent, IDOK, "Background");
                    g_hwndIndexDialog = hdlg;
                    hThread = CreateThread(NULL,0,IndexChats,&g_hwndIndexDialog,0,&dwThreadId);
					if (!hThread)
						MessageBox(g_hwndParent,"Could not start thread","Thread start failed",MB_OK|MB_ICONEXCLAMATION);
					SetWindowText(g_hwndParent,"Index chats from database in GDS");
					//IndexChats((void*)&hdlg);
				}
				else
				{
					if (g_nIconIndex<0)
						ActivateBackgroundMode();
					else
						RestoreNormalMode();
				}
				break;
				
			case IDCANCEL:
				PostMessage(GetParent(hdlg), WM_CLOSE, 0, 0);
				break;
		}
		break;
	}
	return FALSE;
}


BOOL CALLBACK FinishedPageProc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	
	switch(message)
	{
		case WM_INITDIALOG:
		SendMessage(GetParent(hdlg), WIZM_DISABLEBUTTON, 0, 0);
		SendMessage(GetParent(hdlg), WIZM_DISABLEBUTTON, 1, 0);
		SendMessage(GetParent(hdlg), WIZM_SETCANCELTEXT, 0, (LPARAM)("Finish"));
		CheckDlgButton(hdlg, IDC_DONTLOADPLUGIN, BST_UNCHECKED);
		return TRUE;
		
		case WM_COMMAND:
		switch(LOWORD(wParam))
		{
			case IDOK:
			case IDCANCEL:
				if(IsDlgButtonChecked(hdlg, IDC_DONTLOADPLUGIN))
				{			
					char sModuleFileName[MAX_PATH];
					char *pszFileName;
					
					GetModuleFileName(hInst, sModuleFileName, sizeof(sModuleFileName));
					pszFileName = strrchr(sModuleFileName, '\\' );
					if (pszFileName == NULL)
						pszFileName = sModuleFileName;
					else
						pszFileName++;
					// We must lower case here because if a DLL is loaded in two
					// processes, its file name from GetModuleFileName in one process may
					// differ in case from its file name in the other process. This will
					// prevent the plugin from disabling/enabling correctly (this fix relies
					// on the plugin loader to ignore case)
					CharLower(pszFileName);
					DBWriteContactSettingByte(NULL, "PluginDisable", pszFileName, 1);
				}
				PostMessage(GetParent(hdlg), WM_CLOSE, 0, 0);
				break;
		}
		break;
	}
	return FALSE;
}



BOOL CALLBACK WizardDlgProc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	
	static HWND hwndPage;
	

	switch (message)
	{
	case WM_TRAY_ICON_NOTIFY_MESSAGE:
		OnTrayNotify(wParam,lParam);
		break;
		
	case WM_INITDIALOG:
		//TranslateDialogDefault(hdlg);
		hwndPage = CreateDialog(hInst, MAKEINTRESOURCE(IDD_WIZARDINTRO), hdlg, WizardIntroPageProc);
		SetWindowPos(hwndPage, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
		ShowWindow(hwndPage, SW_SHOW);
		ShowWindow(hdlg, SW_SHOW);
		SendMessage(hdlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON1)));
		return TRUE;

	case WIZM_GOTOPAGE:
		DestroyWindow(hwndPage);
		EnableWindow(GetDlgItem(hdlg, IDC_BACK), TRUE);
		EnableWindow(GetDlgItem(hdlg, IDOK), TRUE);
		EnableWindow(GetDlgItem(hdlg, IDCANCEL), TRUE);
		SetDlgItemText(hdlg, IDCANCEL, "Cancel");
		hwndPage = CreateDialog(hInst, MAKEINTRESOURCE(wParam), hdlg, (DLGPROC)lParam);
		SetWindowPos(hwndPage, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
		ShowWindow(hwndPage, SW_SHOW);
		break;

	case WIZM_DISABLEBUTTON:
		switch (wParam)
		{

		case 0:
			EnableWindow(GetDlgItem(hdlg, IDC_BACK), FALSE);
			break;

		case 1:
			EnableWindow(GetDlgItem(hdlg, IDOK), FALSE);
			break;

		case 2:
			EnableWindow(GetDlgItem(hdlg, IDCANCEL), FALSE);
			break;

		}
		break;

	case WIZM_ENABLEBUTTON:
		switch (wParam)
		{

		case 0:
			EnableWindow(GetDlgItem(hdlg, IDC_BACK), TRUE);
			break;

		case 1:
			EnableWindow(GetDlgItem(hdlg, IDOK), TRUE);
			break;

		case 2:
			EnableWindow(GetDlgItem(hdlg, IDCANCEL), TRUE);
			break;

		}
		break;

	case WIZM_SETCANCELTEXT:
		SetDlgItemText(hdlg, IDCANCEL, (char*)lParam);
		break;

	case WM_COMMAND:
		SendMessage(hwndPage, WM_COMMAND, wParam, lParam);
		break;

	case WM_CLOSE:
		if (hThread!=NULL)
			ActivateBackgroundMode();
		else
		{
			DestroyWindow(hwndPage);
			DestroyWindow(hdlg);
		}
		break;
		
	}
	
	return FALSE;
}


void FillContactsArray(HWND hdlg)
{
	HANDLE hContact,hItem = NULL;
	g_nCount = 0;
	if (g_hContacts)
	{
		free(g_hContacts);
		g_hContacts = NULL;
	}
	hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
  do {
       hItem = (HANDLE) SendDlgItemMessage(hdlg, IDC_CLIST, CLM_FINDCONTACT, (WPARAM) hContact, 0);
       if (hItem && SendDlgItemMessage(hdlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM) hItem, 0)) {
					g_nCount++;	
					g_hContacts = (HANDLE*)realloc(g_hContacts,g_nCount*sizeof(HANDLE));
					g_hContacts[g_nCount-1]=hContact;
			 }

	} while (hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0));
}


void InitIndexDialog(HWND hdlg)
{
	g_hwndDialog = hdlg;	
	if (g_hContacts && g_nCount>0)
	{
		char sMsg[255];
		int  nMsgCount = CallService(MS_DB_EVENT_GETCOUNT,(WPARAM)g_hContacts[0], 0);
    char * contactName = (char *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)g_hContacts[0], 0);
		sprintf(sMsg,"%s (0/%d)\0",contactName,nMsgCount);
		SendDlgItemMessage(hdlg,IDC_CONTACTNAME,WM_SETTEXT,0,(LPARAM)sMsg);
		sprintf(sMsg,"0/%d",g_nCount);
		SendDlgItemMessage(hdlg,IDC_PROGRESS,WM_SETTEXT,0,(LPARAM)sMsg);
	}
	InitializeCriticalSection(&Sect1);
}

void	UpdateInfoOnMsg(HWND hdlg,HANDLE hContact, int nProgress,int nTotal)
{
	if (hContact)
	{
		char sMsg[255];
		int  nMsgCount = CallService(MS_DB_EVENT_GETCOUNT,(WPARAM)hContact, 0);
		char * contactName = (char *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0);
		//sprintf(sMsg,"%s (%d/%d)\0",contactName,nProgress,nMsgCount);
		//SendDlgItemMessage(hdlg,IDC_CONTACTNAME,WM_SETTEXT,0,(LPARAM)sMsg);
		//sprintf(sMsg,"%d/%d",nTotal,g_nCount);
		//SendDlgItemMessage(hdlg,IDC_PROGRESS,WM_SETTEXT,0,(LPARAM)sMsg);
		SendDlgItemMessage(hdlg,IDC_PROGRESS_CONTACT,PBM_SETPOS,nProgress,0);
		//SendDlgItemMessage(hdlg,IDC_PROGRES_TOTAL,PBM_SETPOS,nTotal,0);
	}
}

void	UpdateInfoOnContact(HWND hdlg,HANDLE hContact,int nTotal)
{
	if (hContact)
	{
		char sMsg[255];
		int  nMsgCount = CallService(MS_DB_EVENT_GETCOUNT,(WPARAM)hContact, 0);
		char * contactName = (char *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0);
		sprintf(sMsg,"%s (%d)",contactName,nMsgCount);
		SendDlgItemMessage(hdlg,IDC_CONTACTNAME,WM_SETTEXT,0,(LPARAM)sMsg);
		sprintf(sMsg,"%d/%d",nTotal,g_nCount);
		ZeroMemory(g_szToolTip,500);
		
		sprintf(g_szToolTip,"Working: %s -(%s)",contactName,sMsg);
		SendDlgItemMessage(hdlg,IDC_PROGRESS,WM_SETTEXT,0,(LPARAM)sMsg);
		SendDlgItemMessage(hdlg,IDC_PROGRESS_CONTACT,PBM_SETRANGE,0,MAKELPARAM(0, nMsgCount));
		SendDlgItemMessage(hdlg,IDC_PROGRESS_CONTACT,PBM_SETPOS,0,0);
		SendDlgItemMessage(hdlg,IDC_PROGRES_TOTAL,PBM_SETRANGE,0,MAKELPARAM(0, g_nCount));
		SendDlgItemMessage(hdlg,IDC_PROGRES_TOTAL,PBM_SETPOS,nTotal,0);
	}
}




DWORD _stdcall IndexChats(void * pData)
{
	HWND hdlg = *(HWND*)pData;
	if (g_hContacts && g_nCount>0)
	{
		char * szMsg		= NULL;
		char * szUser		= NULL;
		char * szBuddy	= NULL;
		for (int i=0;i<g_nCount;i++)
		{
			EnterCriticalSection(&Sect1);
			UpdateInfoOnContact(hdlg,g_hContacts[i],i+1);
			LeaveCriticalSection(&Sect1);
			g_nCurrent = i+1;
			DBEVENTINFO dbei;
			HANDLE hDbeEvent = (HANDLE)CallService(MS_DB_EVENT_FINDFIRST,(WPARAM)g_hContacts[i], 0);
			int nMessageCount = 0;
			do {
				//////////////////////////////////////////////////////////////////////////
				int nSize = CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)hDbeEvent,(LPARAM)0);
				if (nSize==-1)
					continue;
				ZeroMemory(&dbei,sizeof(dbei));
				dbei.cbSize=sizeof(dbei);
				dbei.cbBlob=nSize;
				dbei.pBlob=(PBYTE)malloc(dbei.cbBlob);
				CallService(MS_DB_EVENT_GET,(WPARAM)hDbeEvent,(LPARAM)&dbei);
				szMsg = (char*)dbei.pBlob;

				CONTACTINFO ci;
				ZeroMemory(&ci,sizeof(ci));

				szUser = "Me";
				ci.cbSize = sizeof(ci);
				ci.hContact = NULL;
				ci.szProto = dbei.szModule;
				ci.dwFlag = CNF_DISPLAY;
				if (!CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) {
					szUser = ci.pszVal;
				}
				nMessageCount++;
				szBuddy = (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)g_hContacts[i],0);
				//LogToFile(szUser,szBuddy,szMsg,dbei.timestamp,(dbei.flags&DBEF_SENT)>0);
				UpdateInfoOnMsg(hdlg,g_hContacts[i],nMessageCount,i+1);
				CallService("Mir2GDS/IndexThis",(WPARAM)g_hContacts[i],(LPARAM)hDbeEvent);
				//////////////////////////////////////////////////////////////////////////
				hDbeEvent=(HANDLE)CallService(MS_DB_EVENT_FINDNEXT,(WPARAM)hDbeEvent, 0);
			} while( hDbeEvent );
		}//for (int i=0;i<g_nCount;i++)
	}//end if
	RestoreNormalMode();
	PostMessage(GetParent(hdlg), WIZM_GOTOPAGE, IDD_FINISHED, (LPARAM)FinishedPageProc);
	SetDlgItemText(g_hwndParent, IDOK, "Finish");
	hThread = NULL;
	SetWindowText(g_hwndParent,"Index chats from database in GDS");
	return 0;
}

void  LogToFile(char * szUser,char * szBuddy,char * szMsg,DWORD & timespan,bool bIsSent)
{
	if (szUser && szBuddy && szMsg)
	{
		FILE * fOut = fopen("c:\\temp\\mir2gds.log","a+");
		if (!fOut)
			return;

		char tmpbuf[128];
		DBTIMETOSTRING db;
		db.cbDest = 128;
		db.szFormat = "d, t";
		db.szDest = tmpbuf;
		CallService(MS_DB_TIME_TIMESTAMPTOSTRING,(WPARAM)timespan,(LPARAM)&db);
		if (bIsSent)
			fprintf(fOut,"From:%s\nTo:%s\nTime:%s\nMsg:%s\n",szUser,szBuddy,tmpbuf,szMsg);
		else
			fprintf(fOut,"From:%s\nTo:%s\nTime:%s\nMsg:%s\n",szBuddy,szUser,tmpbuf,szMsg);
		fprintf(fOut,"-----------------------------------------------------------------\n");
		//fprintf(fOut,"User:%s,Buddy:%s,Msg:%s\n---------------------------------\n",szUser,szBuddy,szMsg);
		fclose(fOut);
	}
}

void  ActivateBackgroundMode()
{
	g_iconData.cbSize	= sizeof(NOTIFYICONDATA);
	g_iconData.hWnd		= g_hwndParent;
	g_iconData.uID		= 1;
	g_iconData.uFlags   = NIF_MESSAGE;
	g_iconData.uCallbackMessage = WM_TRAY_ICON_NOTIFY_MESSAGE;
	HICON hIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON1));
	if (hIcon)
	{
		g_iconData.uFlags   |= NIF_ICON;
		g_iconData.hIcon	= hIcon;
	}
	BOOL bSuccess = Shell_NotifyIcon(NIM_ADD,&g_iconData);
	if (bSuccess)
		g_nIconIndex = 0;

	//ShowWindow(g_hwndParent,SW_HIDE);
	AnimateWindow(g_hwndParent,200,AW_HIDE|AW_BLEND);
	if (!SetTimer(g_hwndDialog,BackgroundTimer,150,NULL))
		MessageBox(g_hwndDialog,"Can't create timer","DB2GDS Error",MB_OK|MB_ICONERROR);
}

void RestoreNormalMode()
{
	KillTimer(g_hwndDialog,BackgroundTimer);
	//ShowWindow(g_hwndParent,SW_SHOW);
	AnimateWindow(g_hwndParent,200,AW_ACTIVATE|AW_BLEND);
	Shell_NotifyIcon(NIM_DELETE,&g_iconData);
	g_nIconIndex = -1;
	SetForegroundWindow(g_hwndParent);
	SetFocus(g_hwndParent);
}

void OnTimer(HWND hWnd,UINT nId)
{
	if (nId!=BackgroundTimer)
		return;
	if (g_nIconIndex<0)
	{
		KillTimer(g_hwndDialog,BackgroundTimer);
		return;
	}
	if (--g_nIconIndex<0)
		g_nIconIndex = 3;
	HICON hNewIcon = NULL;
	switch (g_nIconIndex)
	{
	case 0: hNewIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON1));
			break;
	case 1: hNewIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON2));
			break;
	case 2: hNewIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON3));
			break;
	case 3: hNewIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON4));
			break;
	}
	if (hNewIcon)
	{
		g_iconData.hIcon = hNewIcon;
		Shell_NotifyIcon(NIM_MODIFY,&g_iconData);
	}
}

void	OnTrayNotify(WPARAM wParam, LPARAM lParam)
{
    UINT uID; 
    UINT uMsg; 
 
    uID = (UINT) wParam; 
    uMsg = (UINT) lParam; 
 
	if (uID != 1)
		return;

    switch (uMsg ) 
	{ 
	case WM_MOUSEMOVE:
		{
			int nLength = strlen(g_szToolTip);
			if (nLength>0 && nLength < 64)
			{
				strncpy(g_iconData.szTip,g_szToolTip,nLength);
				g_iconData.uFlags|=NIF_TIP;
				Shell_NotifyIcon(NIM_MODIFY,&g_iconData);
			}
		}
		break;
	case WM_LBUTTONDOWN:
	case WM_LBUTTONDBLCLK:
		RestoreNormalMode();
		break;
    } 
     return; 
}
